import {designComponent, onMounted, reactive} from 'plain-ui-composition';
import './ThemeEditPanel.scss'
import {getConfiguration} from "./sass.utils";
import {deepcopy} from "plain-utils/object/deepcopy";
import {$$dialog, $$loading, PlColorPicker, PlDropdown, PlDropdownMenu, PlDropdownOption, PlIcon, PlNumber, PlScroll} from "plain-ui";
import {downloadText} from "./download.utils";
import {defer} from "plain-utils/utils/defer";
import {buildConfig} from "../../../env/env";


type PromiseType<T> = T extends Promise<infer R> ? R : never

enum EditType {
    color = 'color',
    number = 'number',
}

const EditConfig = [
    {
        title: 'Status',
        tip: '状态色',
        data: [
            {title: 'Primary', tip: '基础', key: 'colorPrimary', type: EditType.color,},
            {title: 'Success', tip: '成功', key: 'colorSuccess', type: EditType.color,},
            {title: 'Warn', tip: '警告', key: 'colorWarn', type: EditType.color,},
            {title: 'Error', tip: '错误', key: 'colorError', type: EditType.color,},
            {title: 'info', tip: '帮助', key: 'colorInfo', type: EditType.color,},
        ]
    },
    {
        title: 'Color',
        tip: '其他颜色',
        data: [
            {title: 'Border', tip: '边框色', key: 'ibc', type: EditType.color,},
            {title: 'Border(light)', tip: '边框色(轻)', key: 'ibl', type: EditType.color,},
            {title: 'Text', tip: '文本色', key: 'itc', type: EditType.color,},
            {title: 'Text(light)', tip: '文本色(轻)', key: 'itl', type: EditType.color,},
            {title: 'Head', tip: '标题色', key: 'ihc', type: EditType.color,},
            {title: 'Placeholder', tip: '占位符颜色', key: 'ipc', type: EditType.color,},
            {title: 'Icon', tip: '图标色', key: 'icc', type: EditType.color,},
        ]
    },
    {
        title: 'Disabled',
        tip: '禁用色',
        data: [
            {title: 'Disabled', tip: '禁用', key: 'disabled', type: EditType.color,},
            {title: 'Disabled(light)', tip: '禁用(轻)', key: 'disabledLight', type: EditType.color,},
            {title: 'Disabled(deep)', tip: '禁用(深)', key: 'disabledDeep', type: EditType.color,},
            {title: 'Disabled(text)', tip: '禁用字体', key: 'disabledText', type: EditType.color,},
        ],
    },
    {
        title: 'Size',
        tip: '尺寸',
        data: [
            {title: 'Large', tip: '大尺寸', key: 'sizeLarge', type: EditType.number,},
            {title: 'Normal(default)', tip: '中尺寸', key: 'sizeNormal', type: EditType.number,},
            {title: 'Mini', tip: '小尺寸', key: 'sizeMini', type: EditType.number,},
            {title: 'Fillet', tip: '圆角大小', key: 'shapeFillet', type: EditType.number,},
        ],
    },
]

/**
 * 在线主题配置缓存
 * @author  韦胜健
 * @date    2021/1/28 14:42
 */
const ThemeCache = (() => {
    const THEME_STORAGE = '@@THEME_STORAGE_DESIGN' + buildConfig.publicPath

    let data: {
        themeData?: Record<string, string>,
        code?: string
    } = {}

    const cache = window.localStorage.getItem(THEME_STORAGE)
    if (!!cache) {
        data = JSON.parse(cache) as any
    }

    return {
        data,
        storage: (themeData: Record<string, string>, code: string) => {
            window.localStorage.setItem(THEME_STORAGE, JSON.stringify({themeData, code,}))
        },
        clear: () => {
            window.localStorage.removeItem(THEME_STORAGE)
        },
    }
})();

/**
 * 使用主题
 * @author  韦胜健
 * @date    2021/1/28 14:42
 */
const UseTheme = (() => {
    const useCode = (code: string) => {
        let el = document.querySelector('#custom-theme')
        if (!el) {
            el = document.createElement('style')
            el.setAttribute('id', 'custom-theme')
            document.body.appendChild(el)
        }
        el.innerHTML = code
    }
    const useTheme = async (themeData: Record<string, string>, themeCompiler: (themeData: Record<string, string>, themeName: string) => Promise<string>) => {
        const code = await themeCompiler(themeData, '')
        useCode(code)
        ThemeCache.storage(themeData, code)
    }
    // 检查是否有缓存，有的话就立即初始化缓存主题
    if (!!ThemeCache.data.code) {useCode(ThemeCache.data.code)}
    return useTheme
})();

/**
 * 主题编辑器相关
 * @author  韦胜健
 * @date    2021/1/28 14:42
 */
export const ThemeEditor = (() => {
    const state = reactive({
        configuration: null as null | PromiseType<ReturnType<typeof getConfiguration>>,
        data: {} as Record<string, string>,
        initPromise: null as null | Promise<void>,
    })
    const utils = {
        init: () => {
            if (!state.initPromise) {
                const dfd = defer<void>()
                const $loadingBar = $$loading.bar;
                (async () => {
                    state.initPromise = dfd.promise as any;
                    const loading = await $loadingBar()
                    try {
                        state.configuration = await getConfiguration()
                        state.data = ThemeCache.data.themeData || deepcopy(state.configuration.defaultEditData)
                        dfd.resolve()
                        loading.done()
                    } catch (e) {
                        dfd.reject()
                        loading.fail()
                    }
                })();
            }
            return state.initPromise!
        },
        getUserThemeName: () => {
            const dfd = defer<string>()
            $$dialog({
                title: '请输入主题名称(为空则主题应用在html下)',
                editValue: '',
                editType: 'input',
                confirmButton: true,
                cancelButton: true,
                onConfirm: async (themeName) => dfd.resolve(themeName || '')
            })
            return dfd.promise
        },
    }

    const methods = {
        apply: async () => {
            await utils.init()
            await methods.useThemeData(state.data)
        },
        reset: async () => {
            /*await utils.init()
           await methods.apply()*/
            state.data = deepcopy(state.configuration!.defaultEditData)
            const el = document.querySelector('#custom-theme')
            el?.parentNode?.removeChild(el)
            ThemeCache.clear()
        },
        useThemeData: async (themeData: Record<string, string>) => {
            await utils.init()
            state.data = themeData
            await UseTheme(themeData, state.configuration!.generateCssFile)
        },
        downloadVariables: async () => {
            const themeName = await utils.getUserThemeName()
            const variables = await state.configuration!.generateVariables(state.data, themeName)
            await downloadText(variables, `${!!themeName ? `theme-${themeName}` : "default"}.scss`)
        },
        downloadCssFile: async () => {
            const themeName = await utils.getUserThemeName()
            const cssText = await state.configuration!.generateCssFile(state.data, themeName)
            await downloadText(cssText, `${!!themeName ? `theme-${themeName}` : "default"}.css`)
        },
        downloadVariablesJson: async () => {
            $$dialog({
                title: '主题变量json数据',
                editType: 'textarea',
                editValue: JSON.stringify(state.data),
                editReadonly: true,
            })
        }
    }


    return {
        state,
        utils,
        methods,
    }
})();

export const ThemeEditPanel = designComponent({
    setup() {

        const {state, methods, utils} = ThemeEditor

        onMounted(utils.init)

        return {
            render: () => (
                <div class="doc-theme-color-panel">
                    <div class="doc-theme-color-panel-head">
                        <div onClick={methods.apply}>
                            <PlIcon icon="el-icon-debug-s"/>
                            <span>应用</span>
                        </div>
                        <div onClick={methods.reset}>
                            <PlIcon icon="el-icon-refresh"/>
                            <span>重置</span>
                        </div>
                        <PlDropdown width="140" placement="bottom-end">
                            {{
                                default: () => (
                                    <div>
                                        <PlIcon icon="el-icon-download"/>
                                        <span>下载</span>
                                    </div>
                                ),
                                popper: () => (
                                    <PlDropdownMenu>
                                        <PlDropdownOption label="下载主题变量" icon="el-icon-debug-s" onClick={methods.downloadVariables}/>
                                        <PlDropdownOption label="下载主题样式" icon="el-icon-document" onClick={methods.downloadCssFile}/>
                                        <PlDropdownOption label="下载JSON数据" icon="el-icon-edit-outline" onClick={methods.downloadVariablesJson}/>
                                    </PlDropdownMenu>
                                )
                            }}
                        </PlDropdown>
                    </div>
                    <div class="doc-theme-color-panel-body">
                        <PlScroll>
                            <div class="doc-theme-color-panel-content">
                                {EditConfig.map((group) => (
                                    <div key={group.title}>
                                        <div class="doc-theme-color-panel-group-title">
                                            <span>{group.title}</span>
                                            <span>{group.tip}</span>
                                        </div>
                                        {group.data.map((item, index) => (
                                            <div key={index} class="doc-theme-color-panel-item">
                                                <div class="doc-theme-color-panel-group-item-title">
                                                    <span>{item.title}</span>
                                                    <span>{item.tip}</span>
                                                </div>
                                                <div>
                                                    {item.type === EditType.color ? (
                                                        <PlColorPicker v-model={state.data[item.key]}/>
                                                    ) : (
                                                        <PlNumber v-model={state.data[item.key]}/>
                                                    )}
                                                </div>
                                            </div>
                                        ))}
                                    </div>
                                ))}
                            </div>
                        </PlScroll>
                    </div>
                </div>
            )
        }
    },
})
